using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.BusinessResearchProductStates.Entities.ResearchState;
using RPESGResearchState = Sustainalytics.ESG.Entities.RPESGResearchState;
using MongoDB.Driver;

namespace Sustainalytics.DataLayer.EsgRatings
{
    public class CorporateDataManagement
    {
        private readonly IMongoCollection<CorporateData> _corporateDataRepository;
        private readonly IMongoCollection<RPESGResearchState> _profileResearchStateRepository;

        public CorporateDataManagement(IMongoCollection<CorporateData> corporateDataRepository, IMongoCollection<RPESGResearchState> profileResearchStateRepository)
        {
            _corporateDataRepository = corporateDataRepository;
            _profileResearchStateRepository = profileResearchStateRepository;
        }

        public async Task<IList<CorporateData>> GetCompaniesWithEsgResearchAsync(int? skip = null, int? take = null, IEnumerable<Guid> companyIds = null)
        {
            Expression<Func<CorporateData, bool>> filter;
            if (companyIds != null)
            {
                filter = x => x.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable && companyIds.Contains(x.Id);
            }
            else
            {
                filter = x => x.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable;
            }

            var corporateDatas = await _corporateDataRepository.Find(filter)
                .Skip(skip)
                .Limit(take)
                .ToListAsync()
                .ConfigureAwait(false);

            return corporateDatas;
        }

        public async Task<Dictionary<Guid, CorporateData>> GetCompaniesWithResearchAsync(int? skip = null, int? take = null, IEnumerable<Guid> companyIds = null)
        {
            Expression<Func<CorporateData, bool>> filter;
            if (companyIds != null)
            {
                filter = x => (x.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable || x.CoreEsgResearchState.ResearchState == ResearchState.ResearchAvailable) && companyIds.Contains(x.Id);
            }
            else
            {
                filter = x => x.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable || x.CoreEsgResearchState.ResearchState == ResearchState.ResearchAvailable;
            }

            var cursor = _corporateDataRepository
                .Find(filter)
                .Limit(take)
                .Skip(skip);
            var corporateDatas = await cursor
                .ToListAsync().ConfigureAwait(false);

            return corporateDatas.ToDictionary(x => x.Id);
        }

        public Task<List<Guid>> GetCorporateDataIdsWithEsgResearch(int? skip = null, int? take = null)
        {
            return _corporateDataRepository.Find(x => x.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable)
                .Skip(skip)
                .Limit(take)
                .Project(x => x.Id)
                .ToListAsync();

        }

        public Task<List<CorporateData>> GetCoverageCompanies()
        {
            return
                _corporateDataRepository.Find(
                x => x.ResearchParentId != null).ToListAsync();
        }

        public async Task<IList<CorporateData>> GetFilteredCompaniesWithEsgResearchAsync(int? skip = null, int? take = null, Guid? accountId = null, Guid? esgProfileId = null, Guid? matrixId = null)
        {
            var corporateDatas = await GetCompaniesWithEsgResearchAsync(skip, take).ConfigureAwait(false);
            var companiesIds = corporateDatas.Select(x => x.Id);
            var researchState = await _profileResearchStateRepository.Find(x => companiesIds.Contains(x.CompanyId) && x.AccountId == accountId && x.EsgProfileId == esgProfileId && x.MatrixId == matrixId).ToListAsync().ConfigureAwait(false);
            return corporateDatas.Join(researchState, x => x.Id, rs => rs.CompanyId, (company, rs) => company).ToList();
        }

        public async Task<List<Guid>> GetFilteredCorporateDataIdsWithEsgResearch(int? skip = null, int? take = null, Guid? accountId = null, Guid? esgProfileId = null, Guid? matrixId = null)
        {
            var corporateDataIds = await GetCorporateDataIdsWithEsgResearch(skip, take).ConfigureAwait(false);
            var researchState = await _profileResearchStateRepository.Find(x => corporateDataIds.Contains(x.CompanyId) && x.AccountId == accountId && x.EsgProfileId == esgProfileId && x.MatrixId == matrixId).ToListAsync();
            return corporateDataIds.Join(researchState, x => x, rs => rs.CompanyId, (company, rs) => company).ToList();
        }
    }
}
